package com.pine.dbant.common.plugin.meta.function.jdbc;

import com.google.common.collect.Lists;
import com.pine.dbant.common.model.Index;
import com.pine.dbant.common.plugin.meta.AbstractQueryMetadataFunction;
import com.pine.dbant.common.plugin.meta.JdbcMetaAnalysisException;
import com.pine.dbant.common.plugin.meta.JdbcMetadataAnalysisConfig;
import com.pine.dbant.common.plugin.meta.QueryMetadataParam;
import lombok.extern.slf4j.Slf4j;

import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
 * @author xiaoyuan
 * @create 2023/1/4 10:53
 **/
@Slf4j
public class TableIndexFunction extends AbstractQueryMetadataFunction<JdbcMetadataAnalysisConfig, List> {
    protected static final String TABLE_CAT = "TABLE_CAT";
    protected static final String TABLE_CATALOG = "TABLE_CATALOG";
    protected static final String TABLE_SCHEM = "TABLE_SCHEM";
    protected static final String TABLE_NAME = "TABLE_NAME";
    protected static final String TABLE_TYPE = "TABLE_TYPE";
    protected static final String REMARKS = "REMARKS";
    protected static final String COLUMN_NAME = "COLUMN_NAME";
    protected static final String ASC_OR_DESC = "ASC_OR_DESC";
    protected static final String INDEX_QUALIFIER = "INDEX_QUALIFIER";
    protected static final String DATA_TYPE = "DATA_TYPE";
    protected static final String TYPE_NAME = "TYPE_NAME";
    protected static final String COLUMN_SIZE = "COLUMN_SIZE";
    protected static final String BUFFER_LENGTH = "BUFFER_LENGTH";
    protected static final String DECIMAL_DIGITS = "DECIMAL_DIGITS";
    protected static final String NUM_PREC_RADIX = "NUM_PREC_RADIX";
    protected static final String NULLABLE = "NULLABLE";
    protected static final String COLUMN_DEF = "COLUMN_DEF";
    protected static final String SQL_DATA_TYPE = "SQL_DATA_TYPE";
    protected static final String SQL_DATETIME_SUB = "SQL_DATETIME_SUB";
    protected static final String CHAR_OCTET_LENGTH = "CHAR_OCTET_LENGTH";
    protected static final String ORDINAL_POSITION = "ORDINAL_POSITION";
    protected static final String IS_NULLABLE = "IS_NULLABLE";
    protected static final String SCOPE_CATALOG = "SCOPE_CATALOG";
    protected static final String SCOPE_SCHEMA = "SCOPE_SCHEMA";
    protected static final String SCOPE_TABLE = "SCOPE_TABLE";
    protected static final String SOURCE_DATA_TYPE = "SOURCE_DATA_TYPE";
    protected static final String TYPE = "TYPE";
    protected static final String NON_UNIQUE = "NON_UNIQUE";
    protected static final String INDEX_NAME = "INDEX_NAME";
    protected static final String KEY_SEQ = "KEY_SEQ";
    protected static final String PK_NAME = "PK_NAME";
    /**
     * 一般数据库的判断自增的属性名
     */
    protected static final String IS_AUTOINCREMENT = "IS_AUTOINCREMENT";

    public TableIndexFunction(String type) {
        super(type);
    }

    @Override
    public List<Index> doQuery(JdbcMetadataAnalysisConfig metadataAnalysisConfig, QueryMetadataParam queryMetadataParam) {
        DatabaseMetaData dbMetaData;
        try {
            dbMetaData = metadataAnalysisConfig.getConnection().getMetaData();
        } catch (SQLException e) {
            throw new JdbcMetaAnalysisException(e.getMessage(), e);
        }
        String catalog = queryMetadataParam.getConfiguration().getNecessaryValue("catalog");
        String tableName = queryMetadataParam.getConfiguration().getNecessaryValue("tableName");
        return buildIndex(dbMetaData,catalog,null,tableName);
    }


    protected   List<Index> buildIndex(DatabaseMetaData dbMetaData, String catalog, String schemaName, String tableName) {
        List<Index> indices = Lists.newArrayList();
        /**
         * catalog : 类别名称，因为存储在此数据库中，所以它必须匹配类别名称。该参数为 “” 则检索没有类别的描述，为 null 则表示该类别名称不应用于缩小搜索范围
         * schema : 模式名称，因为存储在此数据库中，所以它必须匹配模式名称。该参数为 “” 则检索那些没有模式的描述，为 null 则表示该模式名称不应用于缩小搜索范围
         * table : 表名称，因为存储在此数据库中，所以它必须匹配表名称
         * unique : 该参数为 true 时，仅返回惟一值的索引；该参数为 false 时，返回所有索引，不管它们是否惟一
         * approximate : 该参数为 true 时，允许结果是接近的数据值或这些数据值以外的值；该参数为 false 时，要求结果是精确结果
         */
        try (ResultSet rs = dbMetaData.getIndexInfo(catalog, schemaName, tableName, false, false)) {
            while (rs.next()) {
                String tbCatalog = rs.getString(TABLE_CAT);
                String tbSchema = rs.getString(TABLE_SCHEM);
                String tbName = rs.getString(TABLE_NAME);
                // 非唯一索引(Can
                // index values
                // be
                // non-unique.
                // false when
                // TYPE is
                // tableIndexStatistic
                // )
                short type = rs.getShort(TYPE);
                if (type == 0) {
                    continue;
                }
                boolean nonUnique = rs.getBoolean(NON_UNIQUE);
                // 列名
                String indexQualifier = rs.getString(INDEX_QUALIFIER);
                // 索引的名称
                String indexName = rs.getString(INDEX_NAME);
                // 索引类型

                // 在索引列顺序号
                short ordinalPosition = rs.getShort(ORDINAL_POSITION);
                // 列名
                String columnName = rs.getString(COLUMN_NAME);
                // 列名
                String columnSort = rs.getString(ASC_OR_DESC);

                Index index = new Index();
                index.setCatalogName(tbCatalog);
                index.setSchemaName(tbSchema);
                index.setTableName(tbName);
                index.setColumnName(columnName);
                index.setColumnSort(columnSort);
                index.setIndexType(type);
                index.setIndexName(indexName);
                index.setNonUnique(nonUnique);
                index.setIndexQualifier(indexQualifier);
                index.setOrdinalPosition(ordinalPosition);
                index.setKey(indexName);
                indices.add(index);
            }
        } catch (SQLException e) {
            log.error("获取数据库[{}]下schema[{}]的表[{}]的索引错误", catalog, schemaName, tableName, e);
            //此处错误不往上抛，主要原因是有些驱动不支持查询，需要自己在实现类中通过sql自己查询
        }
        return indices;
    }
}
